package top.zhangjianyong.tools.indicator.strategy.impl;

import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.context.IndicatorContext;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * MFI（资金流量指标）计算器
 * 窗口14，结合价格和成交量的动量指标
 * MFI类似于RSI，但考虑了成交量因素
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Component
public class MFIIndicator extends AbstractIndicator {

    private static final String INDICATOR_NAME = "MFI";
    private static final int PERIOD = 14;

    @Override
    public String getName() {
        return INDICATOR_NAME;
    }

    @Override
    public int getMinDataSize() {
        return PERIOD + 1; // 需要至少15个数据点
    }

    @Override
    protected TechnicalIndicatorResult doCalculate(IndicatorContext context) {
        List<ETFData> dataList = context.getDataList();

        // 计算典型价格和资金流量
        List<BigDecimal> typicalPrices = new ArrayList<>();
        List<BigDecimal> moneyFlows = new ArrayList<>();

        for (int i = 0; i < dataList.size(); i++) {
            ETFData data = dataList.get(i);
            BigDecimal price = data.getValue();
            Long volume = data.getVolume() != null ? data.getVolume() : 0L;

            // 典型价格 = (最高价 + 最低价 + 收盘价) / 3
            // 由于只有收盘价，使用收盘价作为典型价格
            BigDecimal typicalPrice = price;
            typicalPrices.add(typicalPrice);

            // 资金流量 = 典型价格 × 成交量
            BigDecimal moneyFlow = typicalPrice.multiply(BigDecimal.valueOf(volume));
            moneyFlows.add(moneyFlow);
        }

        // 计算MFI
        BigDecimal mfi = calculateMFI(typicalPrices, moneyFlows);

        TechnicalIndicatorResult result = TechnicalIndicatorResult.success(getName());
        if (mfi != null) {
            result.addValue("mfi", mfi.setScale(2, RoundingMode.HALF_UP));
            result.addValue("mfi_14", mfi.setScale(2, RoundingMode.HALF_UP));
        } else {
            return TechnicalIndicatorResult.failure(getName(), "MFI计算失败");
        }

        return result;
    }

    /**
     * 计算MFI（资金流量指标）
     * MFI = 100 - (100 / (1 + 资金流量比率))
     * 资金流量比率 = 正资金流量总和 / 负资金流量总和
     */
    private BigDecimal calculateMFI(List<BigDecimal> typicalPrices, List<BigDecimal> moneyFlows) {
        if (typicalPrices.size() < PERIOD + 1 || moneyFlows.size() < PERIOD + 1) {
            return null;
        }

        // 计算正资金流量和负资金流量
        BigDecimal positiveMoneyFlow = BigDecimal.ZERO;
        BigDecimal negativeMoneyFlow = BigDecimal.ZERO;

        // 从最后PERIOD个数据点开始计算
        int startIndex = typicalPrices.size() - PERIOD;
        for (int i = startIndex; i < typicalPrices.size(); i++) {
            if (i == 0) {
                continue; // 需要前一日数据进行比较
            }

            BigDecimal currentTypicalPrice = typicalPrices.get(i);
            BigDecimal previousTypicalPrice = typicalPrices.get(i - 1);
            BigDecimal currentMoneyFlow = moneyFlows.get(i);

            int comparison = currentTypicalPrice.compareTo(previousTypicalPrice);

            if (comparison > 0) {
                // 价格上涨，计入正资金流量
                positiveMoneyFlow = positiveMoneyFlow.add(currentMoneyFlow);
            } else if (comparison < 0) {
                // 价格下跌，计入负资金流量
                negativeMoneyFlow = negativeMoneyFlow.add(currentMoneyFlow);
            }
        }

        // 如果负资金流量为0，MFI为100
        if (negativeMoneyFlow.compareTo(BigDecimal.ZERO) == 0) {
            return new BigDecimal(100);
        }

        // 计算资金流量比率
        BigDecimal moneyFlowRatio = positiveMoneyFlow.divide(negativeMoneyFlow, 8, RoundingMode.HALF_UP);

        // 计算MFI
        BigDecimal mfi = new BigDecimal(100)
            .subtract(new BigDecimal(100)
                .divide(moneyFlowRatio.add(BigDecimal.ONE), 8, RoundingMode.HALF_UP));

        return mfi.setScale(2, RoundingMode.HALF_UP);
    }
}

